﻿using System;
using System.Linq;
using ForumsBrowser.BusinessObjects;
using ForumsBrowser.ServiceContracts;
using ForumsBrowser.SiteAccess;
using System.Collections.Generic;

namespace ForumsBrowser.ObjectGateway
{
    internal static class ForumGetAction
    {
        static ForumGetAction()
        {
            forumCache = new Dictionary<string, ForumsBrowser.DataObjects.Forum>();
        }

        internal static Dictionary<string, ForumsBrowser.DataObjects.Forum> forumCache;

        internal static Forum Execute(string forumName, DateTime? since)
        {
            // The forum data is not returned if the datetime is sent.
            // So if we haven't fetched it already, we need to get this 
            // information and save it in the cache for later retrieval. 
            if (!forumCache.ContainsKey(forumName) && since.HasValue)
                Execute(forumName, null);

            var data = ServiceFactory.Service.GetPosts(forumName, since);
            Forum result = new Forum();

            if (data != null)
            {
                if (data != null && data.Forum != null) forumCache[forumName] = data.Forum;

                // Use the current data if available, otherwise, pull from the cache. 
                data.Forum = data.Forum ?? forumCache[forumName];

                var users = data.Users.Select(user => TranslateUserAction.Execute(user)).ToList().ToLookup(u => u.Id);
                

                var threads = 
                    data.Threads.Select(t =>
                        new Thread
                        {
                            Title = t.Topic,
                            Id = t.Id,
                            Url = t.Url,
                            CreatedOn = t.CreatedOn.FromXmlToDateTime().Value,
                            Replies = t.Replies,
                            Type = t.Type,
                            Views = t.Views
                        }
                    ).ToList();


                var messages = TranslateMessagesAction.Execute(data.Messages).ToLookup(t => t.Id);

                var messageThreadAssociation = data.Threads.Where(t => t.LastReply != null).Select(t => new { t.LastReply.Id, ThreadId = t.Id }).ToLookup(x => x.Id);
                
                // set the forum name on each item. 
                foreach (var thread in threads)
                    thread.ForumName = data.Forum.DisplayName;
                    
                // Set the author of each message. 
                foreach (var message in data.Messages)
                {
                    messages[message.Id].Single().Author = users[message.AuthorId].Single();

                    var threadId = messageThreadAssociation[message.Id].Single().ThreadId;

                    // add the message to the thread. 
                    threads.First(t => t.Id == threadId).Messages.Add(messages[message.Id].Single());
                }

                // Set the author of each thread. 
                foreach (var thread in data.Threads)
                {
                    var t = threads.First(th => th.Id == thread.Id);

                    // get messages for empty threads. 
                    if (t.Messages.Count == 0)
                    {
                        var detailThread = ThreadGetAction.Execute(t.Url);
                        if (detailThread != null)
                            t.Messages.AddRange(detailThread.Messages);
                    }

                    t.Author = users[thread.AuthorId].Single();

                    if (t.Replies > 0)
                    {
                        var recent = t.Messages.OrderByDescending(x => x.CreatedOn).FirstOrDefault();

                        if (recent != null)
                        {
                            t.LastRepliedOn = recent.CreatedOn;
                            t.LastReplier = recent.Author;
                        }
                    }
                }

                result.ShortName = data.Forum.ShortName;
                result.LongName = data.Forum.DisplayName;
                result.Id = data.Forum.Id;
                result.Updated = since;
                result.Threads = threads.ToList();
                
                return result;
            }
            return null;
        }
    }
}
